home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / doom / suckmods.zip / SUCK05 / SRC / DOORS.QC < prev    next >
Text File  |  1997-05-09  |  17KB  |  791 lines

  1.  
  2. float DOOR_START_OPEN = 1;
  3. float DOOR_DONT_LINK = 4;
  4. float DOOR_GOLD_KEY = 8;
  5. float DOOR_SILVER_KEY = 16;
  6. float DOOR_TOGGLE = 32;
  7.  
  8. /*
  9.  
  10. Doors are similar to buttons, but can spawn a fat trigger field around them
  11. to open without a touch, and they link together to form simultanious
  12. double/quad doors.
  13.  
  14. Door.owner is the master door.  If there is only one door, it points to itself.
  15. If multiple doors, all will point to a single one.
  16.  
  17. Door.enemy chains from the master door through all doors linked in the chain.
  18.  
  19. */
  20.  
  21. /*
  22. =============================================================================
  23.  
  24. THINK FUNCTIONS
  25.  
  26. =============================================================================
  27. */
  28.  
  29. void() door_go_down;
  30. void() door_go_up;
  31.  
  32. void() door_blocked =
  33. {
  34.     T_Damage (other, self, self, self.dmg);
  35.     
  36. // if a door has a negative wait, it would never come back if blocked,
  37. // so let it just squash the object to death real fast
  38.     if (self.wait >= 0)
  39.     {
  40.         if (self.state == STATE_DOWN)
  41.             door_go_up ();
  42.         else
  43.             door_go_down ();
  44.     }
  45. };
  46.  
  47.  
  48. void() door_hit_top =
  49. {
  50.         if (self.activr.rune_num != ITEM_RUNE_NINJA)
  51.     sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  52.     self.state = STATE_TOP;
  53.     if (self.spawnflags & DOOR_TOGGLE)
  54.         return;        // don't come down automatically
  55.     self.think = door_go_down;
  56.     self.nextthink = self.ltime + self.wait;
  57. };
  58.  
  59. void() door_hit_bottom =
  60. {
  61.         if (self.activr.rune_num != ITEM_RUNE_NINJA)
  62.     sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  63.     self.state = STATE_BOTTOM;
  64. };
  65.  
  66. void() door_go_down =
  67. {
  68.         if (self.activr.rune_num != ITEM_RUNE_NINJA)
  69.     sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  70.     if (self.max_health)
  71.     {
  72.         self.takedamage = DAMAGE_YES;
  73.         self.health = self.max_health;
  74.     }
  75.     
  76.     self.state = STATE_DOWN;
  77.     SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
  78. };
  79.  
  80. void() door_go_up =
  81. {
  82.     if (self.state == STATE_UP)
  83.         return;        // allready going up
  84.  
  85.     if (self.state == STATE_TOP)
  86.     {    // reset top wait time
  87.         self.nextthink = self.ltime + self.wait;
  88.         return;
  89.     }
  90.     
  91.         if (self.activr.rune_num != ITEM_RUNE_NINJA)
  92.     sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  93.     self.state = STATE_UP;
  94.     SUB_CalcMove (self.pos2, self.speed, door_hit_top);
  95.  
  96.     SUB_UseTargets();
  97. };
  98.  
  99.  
  100. /*
  101. =============================================================================
  102.  
  103. ACTIVATION FUNCTIONS
  104.  
  105. =============================================================================
  106. */
  107.  
  108. void() door_fire =
  109. {
  110.     local entity     oself;
  111.     local entity    starte;
  112.  
  113.     if (self.owner != self)
  114.         objerror ("door_fire: self.owner != self");
  115.  
  116. // play use key sound
  117.  
  118.     if (self.items)
  119.         if (self.activr.rune_num != ITEM_RUNE_NINJA)
  120.             sound (self, CHAN_VOICE, self.noise4, 1, ATTN_NORM);
  121.  
  122.     self.message = string_null;        // no more message
  123.     oself = self;
  124.  
  125.     if (self.spawnflags & DOOR_TOGGLE)
  126.     {
  127.         if (self.state == STATE_UP || self.state == STATE_TOP)
  128.         {
  129.             starte = self;
  130.             do
  131.             {
  132.                 door_go_down ();
  133.                 self = self.enemy;
  134.             } while ( (self != starte) && (self != world) );
  135.             self = oself;
  136.             return;
  137.         }
  138.     }
  139.     
  140. // trigger all paired doors
  141.     starte = self;
  142.     do
  143.     {
  144.         door_go_up ();
  145.         self = self.enemy;
  146.     } while ( (self != starte) && (self != world) );
  147.     self = oself;
  148. };
  149.  
  150.  
  151. void() door_use =
  152. {
  153.     local entity oself;
  154.  
  155.     self.message = "";            // door message are for touch only
  156.     self.owner.message = "";    
  157.     self.enemy.message = "";
  158.     oself = self;
  159.     self = self.owner;
  160.     door_fire ();
  161.     self = oself;
  162. };
  163.  
  164.  
  165. void() door_trigger_touch =
  166. {
  167.     if (other.health <= 0)
  168.         return;
  169.  
  170.     if (time < self.attack_finished)
  171.         return;
  172.     self.attack_finished = time + 1;
  173.  
  174.     activator = other;
  175.     self.activr=other;
  176.  
  177.     self = self.owner;
  178.     door_use ();
  179. };
  180.  
  181.  
  182. void() door_killed =
  183. {
  184.     local entity oself;
  185.     
  186.     oself = self;
  187.     self = self.owner;
  188.     self.health = self.max_health;
  189.     self.takedamage = DAMAGE_NO;    // wil be reset upon return
  190.     door_use ();
  191.     self = oself;
  192. };
  193.  
  194.  
  195. /*
  196. ================
  197. door_touch
  198.  
  199. Prints messages and opens key doors
  200. ================
  201. */
  202. void() door_touch =
  203. {
  204.     if (other.classname != "player")
  205.         return;
  206.     if (self.owner.attack_finished > time)
  207.         return;
  208.  
  209.     self.owner.attack_finished = time + 2;
  210.  
  211.     if (self.owner.message != "")
  212.     {
  213.         clientmsg (other, self.owner.message);
  214.         if (self.activr.rune_num != ITEM_RUNE_NINJA)
  215.         sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
  216.     }
  217.     
  218. // key door stuff
  219.     if (!self.items)
  220.         return;
  221.  
  222. // FIXME: blink key on player's status bar
  223.     if ( (self.items & other.items) != self.items )
  224.     {
  225.         if (self.owner.items == IT_KEY1)
  226.         {
  227.             if (world.worldtype == 2)
  228.             {
  229.                 centerprint (other, "You need the silver keycard");
  230.                 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  231.             }
  232.             else if (world.worldtype == 1)
  233.             {
  234.                 centerprint (other, "You need the silver runekey");
  235.                 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  236.             }
  237.             else if (world.worldtype == 0)
  238.             {
  239.                 centerprint (other, "You need the silver key");
  240.                 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  241.             }
  242.         }
  243.         else
  244.         {
  245.             if (world.worldtype == 2)
  246.             {
  247.                 centerprint (other, "You need the gold keycard");
  248.                 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  249.             }
  250.             else if (world.worldtype == 1)
  251.             {
  252.                 centerprint (other, "You need the gold runekey");
  253.                 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);            
  254.             }
  255.             else if (world.worldtype == 0)
  256.             {
  257.                 centerprint (other, "You need the gold key");
  258.                 sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  259.             }
  260.         }
  261.         return;
  262.     }
  263.  
  264.     other.items = other.items - self.items;
  265.     self.touch = SUB_Null;
  266.     if (self.enemy)
  267.         self.enemy.touch = SUB_Null;    // get paired door
  268.     door_use ();
  269. };
  270.  
  271. /*
  272. =============================================================================
  273.  
  274. SPAWNING FUNCTIONS
  275.  
  276. =============================================================================
  277. */
  278.  
  279.  
  280. entity(vector fmins, vector fmaxs) spawn_field =
  281. {
  282.     local entity    trigger;
  283.     local    vector    t1, t2;
  284.  
  285.     trigger = spawn();
  286.     trigger.movetype = MOVETYPE_NONE;
  287.     trigger.solid = SOLID_TRIGGER;
  288.     trigger.owner = self;
  289.     trigger.touch = door_trigger_touch;
  290.  
  291.     t1 = fmins;
  292.     t2 = fmaxs;
  293.     setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
  294.     return (trigger);
  295. };
  296.  
  297.  
  298. float (entity e1, entity e2) EntitiesTouching =
  299. {
  300.     if (e1.mins_x > e2.maxs_x)
  301.         return FALSE;
  302.     if (e1.mins_y > e2.maxs_y)
  303.         return FALSE;
  304.     if (e1.mins_z > e2.maxs_z)
  305.         return FALSE;
  306.     if (e1.maxs_x < e2.mins_x)
  307.         return FALSE;
  308.     if (e1.maxs_y < e2.mins_y)
  309.         return FALSE;
  310.     if (e1.maxs_z < e2.mins_z)
  311.         return FALSE;
  312.     return TRUE;
  313. };
  314.  
  315.  
  316. /*
  317. =============
  318. LinkDoors
  319.  
  320.  
  321. =============
  322. */
  323. void() LinkDoors =
  324. {
  325.     local entity    t, starte;
  326.     local vector    cmins, cmaxs;
  327.  
  328.     if (self.enemy)
  329.         return;        // already linked by another door
  330.     if (self.spawnflags & 4)
  331.     {
  332.         self.owner = self.enemy = self;
  333.         return;        // don't want to link this door
  334.     }
  335.  
  336.     cmins = self.mins;
  337.     cmaxs = self.maxs;
  338.     
  339.     starte = self;
  340.     t = self;
  341.     
  342.     do
  343.     {
  344.         self.owner = starte;            // master door
  345.  
  346.         if (self.health)
  347.             starte.health = self.health;
  348.         if (self.targetname)
  349.             starte.targetname = self.targetname;
  350.         if (self.message != "")
  351.             starte.message = self.message;
  352.  
  353.         t = find (t, classname, self.classname);    
  354.         if (!t)
  355.         {
  356.             self.enemy = starte;        // make the chain a loop
  357.  
  358.         // shootable, fired, or key doors just needed the owner/enemy links,
  359.         // they don't spawn a field
  360.     
  361.             self = self.owner;
  362.  
  363.             if (self.health)
  364.                 return;
  365.             if (self.targetname)
  366.                 return;
  367.             if (self.items)
  368.                 return;
  369.  
  370.             self.owner.trigger_field = spawn_field(cmins, cmaxs);
  371.  
  372.             return;
  373.         }
  374.  
  375.         if (EntitiesTouching(self,t))
  376.         {
  377.             if (t.enemy)
  378.                 objerror ("cross connected doors");
  379.             
  380.             self.enemy = t;
  381.             self = t;
  382.  
  383.             if (t.mins_x < cmins_x)
  384.                 cmins_x = t.mins_x;
  385.             if (t.mins_y < cmins_y)
  386.                 cmins_y = t.mins_y;
  387.             if (t.mins_z < cmins_z)
  388.                 cmins_z = t.mins_z;
  389.             if (t.maxs_x > cmaxs_x)
  390.                 cmaxs_x = t.maxs_x;
  391.             if (t.maxs_y > cmaxs_y)
  392.                 cmaxs_y = t.maxs_y;
  393.             if (t.maxs_z > cmaxs_z)
  394.                 cmaxs_z = t.maxs_z;
  395.         }
  396.     } while (1 );
  397.  
  398. };
  399.  
  400.  
  401. /*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
  402. if two doors touch, they are assumed to be connected and operate as a unit.
  403.  
  404. TOGGLE causes the door to wait in both the start and end states for a trigger event.
  405.  
  406. START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
  407.  
  408. Key doors are allways wait -1.
  409.  
  410. "message"    is printed when the door is touched if it is a trigger door and it hasn't been fired yet
  411. "angle"        determines the opening direction
  412. "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
  413. "health"    if set, door must be shot open
  414. "speed"        movement speed (100 default)
  415. "wait"        wait before returning (3 default, -1 = never return)
  416. "lip"        lip remaining at end of move (8 default)
  417. "dmg"        damage to inflict when blocked (2 default)
  418. "sounds"
  419. 0)    no sound
  420. 1)    stone
  421. 2)    base
  422. 3)    stone chain
  423. 4)    screechy metal
  424. */
  425.  
  426. void() func_door =
  427.  
  428. {
  429.  
  430.     if (world.worldtype == 0)
  431.     {
  432.         precache_sound ("doors/medtry.wav");
  433.         precache_sound ("doors/meduse.wav");
  434.         self.noise3 = "doors/medtry.wav";
  435.         self.noise4 = "doors/meduse.wav";
  436.     }
  437.     else if (world.worldtype == 1)
  438.     {
  439.         precache_sound ("doors/runetry.wav");
  440.         precache_sound ("doors/runeuse.wav");
  441.         self.noise3 = "doors/runetry.wav";
  442.         self.noise4 = "doors/runeuse.wav";
  443.     }
  444.     else if (world.worldtype == 2)
  445.     {
  446.         precache_sound ("doors/basetry.wav");
  447.         precache_sound ("doors/baseuse.wav");
  448.         self.noise3 = "doors/basetry.wav";
  449.         self.noise4 = "doors/baseuse.wav";
  450.     }
  451.     else
  452.     {
  453.         dprint ("no worldtype set!\n");
  454.     }
  455.     if (self.sounds == 0)
  456.     {
  457.         precache_sound ("misc/null.wav");
  458.         precache_sound ("misc/null.wav");
  459.         self.noise1 = "misc/null.wav";
  460.         self.noise2 = "misc/null.wav";
  461.     }
  462.     if (self.sounds == 1)
  463.     {
  464.         precache_sound ("doors/drclos4.wav");
  465.         precache_sound ("doors/doormv1.wav");
  466.         self.noise1 = "doors/drclos4.wav";
  467.         self.noise2 = "doors/doormv1.wav";
  468.     }
  469.     if (self.sounds == 2)
  470.     {
  471.         precache_sound ("doors/hydro1.wav");
  472.         precache_sound ("doors/hydro2.wav");
  473.         self.noise2 = "doors/hydro1.wav";
  474.         self.noise1 = "doors/hydro2.wav";
  475.     }
  476.     if (self.sounds == 3)
  477.     {
  478.         precache_sound ("doors/stndr1.wav");
  479.         precache_sound ("doors/stndr2.wav");
  480.         self.noise2 = "doors/stndr1.wav";
  481.         self.noise1 = "doors/stndr2.wav";
  482.     }
  483.     if (self.sounds == 4)
  484.     {
  485.         precache_sound ("doors/ddoor1.wav");
  486.         precache_sound ("doors/ddoor2.wav");
  487.         self.noise1 = "doors/ddoor2.wav";
  488.         self.noise2 = "doors/ddoor1.wav";
  489.     }
  490.  
  491.  
  492.     SetMovedir ();
  493.  
  494.     self.max_health = self.health;
  495.     self.solid = SOLID_BSP;
  496.     self.movetype = MOVETYPE_PUSH;
  497.     setorigin (self, self.origin);    
  498.     setmodel (self, self.model);
  499.     self.classname = "door";
  500.  
  501.     self.blocked = door_blocked;
  502.     self.use = door_use;
  503.     
  504.     if (self.spawnflags & DOOR_SILVER_KEY)
  505.         self.items = IT_KEY1;
  506.     if (self.spawnflags & DOOR_GOLD_KEY)
  507.         self.items = IT_KEY2;
  508.     
  509.     if (!self.speed)
  510.         self.speed = 100;
  511.     if (!self.wait)
  512.         self.wait = 3;
  513.     if (!self.lip)
  514.         self.lip = 8;
  515.     if (!self.dmg)
  516.         self.dmg = 2;
  517.  
  518.     self.pos1 = self.origin;
  519.     self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
  520.  
  521. // DOOR_START_OPEN is to allow an entity to be lighted in the closed position
  522. // but spawn in the open position
  523.     if (self.spawnflags & DOOR_START_OPEN)
  524.     {
  525.         setorigin (self, self.pos2);
  526.         self.pos2 = self.pos1;
  527.         self.pos1 = self.origin;
  528.     }
  529.  
  530.     self.state = STATE_BOTTOM;
  531.  
  532.     if (self.health)
  533.     {
  534.         self.takedamage = DAMAGE_YES;
  535.         self.th_die = door_killed;
  536.     }
  537.     
  538.     if (self.items)
  539.         self.wait = -1;
  540.         
  541.     self.touch = door_touch;
  542.  
  543. // LinkDoors can't be done until all of the doors have been spawned, so
  544. // the sizes can be detected properly.
  545.     self.think = LinkDoors;
  546.     self.nextthink = self.ltime + 0.1;
  547. };
  548.  
  549. /*
  550. =============================================================================
  551.  
  552. SECRET DOORS
  553.  
  554. =============================================================================
  555. */
  556.  
  557. void() fd_secret_move1;
  558. void() fd_secret_move2;
  559. void() fd_secret_move3;
  560. void() fd_secret_move4;
  561. void() fd_secret_move5;
  562. void() fd_secret_move6;
  563. void() fd_secret_done;
  564.  
  565. float SECRET_OPEN_ONCE = 1;        // stays open
  566. float SECRET_1ST_LEFT = 2;        // 1st move is left of arrow
  567. float SECRET_1ST_DOWN = 4;        // 1st move is down from arrow
  568. float SECRET_NO_SHOOT = 8;        // only opened by trigger
  569. float SECRET_YES_SHOOT = 16;    // shootable even if targeted
  570. float SECRET_NEVER = 32;        // lock it shut
  571.  
  572.  
  573. void () fd_secret_use =
  574. {
  575.     local float temp;
  576.     
  577.     self.health = 10000;
  578.  
  579.     // exit if still moving around...
  580.     if (self.origin != self.oldorigin)
  581.         return;
  582.     
  583.     self.message = string_null;        // no more message
  584.  
  585.     SUB_UseTargets();                // fire all targets / killtargets
  586.     
  587.     if (self.spawnflags & SECRET_NEVER)
  588.         return; // it never opens
  589.     
  590.     if (!(self.spawnflags & SECRET_NO_SHOOT))
  591.     {
  592.         self.th_pain = SUB_Null;
  593.         self.takedamage = DAMAGE_NO;
  594.     }
  595.     self.velocity = '0 0 0';
  596.  
  597.     // Make a sound, wait a little...
  598.     
  599.     sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
  600.     self.nextthink = self.ltime + 0.1;
  601.  
  602.     temp = 1 - (self.spawnflags & SECRET_1ST_LEFT);    // 1 or -1
  603.     makevectors(self.mangle);
  604.     
  605.     if (!self.t_width)
  606.     {
  607.         if (self.spawnflags & SECRET_1ST_DOWN)
  608.             self. t_width = fabs(v_up * self.size);
  609.         else
  610.             self. t_width = fabs(v_right * self.size);
  611.     }
  612.         
  613.     if (!self.t_length)
  614.         self. t_length = fabs(v_forward * self.size);
  615.  
  616.     if (self.spawnflags & SECRET_1ST_DOWN)
  617.         self.dest1 = self.origin - v_up * self.t_width;
  618.     else
  619.         self.dest1 = self.origin + v_right * (self.t_width * temp);
  620.         
  621.     self.dest2 = self.dest1 + v_forward * self.t_length;
  622.     SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
  623.     sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  624. };
  625.  
  626. // Wait after first movement...
  627. void () fd_secret_move1 = 
  628. {
  629.     self.nextthink = self.ltime + 1.0;
  630.     self.think = fd_secret_move2;
  631.     sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  632. };
  633.  
  634. // Start moving sideways w/sound...
  635. void () fd_secret_move2 =
  636. {
  637.     sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  638.     SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
  639. };
  640.  
  641. // Wait here until time to go back...
  642. void () fd_secret_move3 =
  643. {
  644.     sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  645.     if (!(self.spawnflags & SECRET_OPEN_ONCE))
  646.     {
  647.         self.nextthink = self.ltime + self.wait;
  648.         self.think = fd_secret_move4;
  649.     }
  650. };
  651.  
  652. // Move backward...
  653. void () fd_secret_move4 =
  654. {
  655.     sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  656.     SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);        
  657. };
  658.  
  659. // Wait 1 second...
  660. void () fd_secret_move5 = 
  661. {
  662.     self.nextthink = self.ltime + 1.0;
  663.     self.think = fd_secret_move6;
  664.     sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  665. };
  666.  
  667. void () fd_secret_move6 =
  668. {
  669.     sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
  670.     SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
  671. };
  672.  
  673. void () fd_secret_done =
  674. {
  675.     if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
  676.     {
  677.         self.health = 10000;
  678.         self.takedamage = DAMAGE_YES;
  679.         self.th_pain = fd_secret_use;    
  680.     }
  681.     sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
  682. };
  683.  
  684. void () secret_blocked =
  685. {
  686.     if (time < self.attack_finished)
  687.         return;
  688.     self.attack_finished = time + 0.5;
  689.     T_Damage (other, self, self, self.dmg);
  690. };
  691.  
  692. /*
  693. ================
  694. secret_touch
  695.  
  696. Prints messages
  697. ================
  698. */
  699. void() secret_touch =
  700. {
  701.     if (other.classname != "player")
  702.         return;
  703.     if (self.attack_finished > time)
  704.         return;
  705.  
  706.     self.attack_finished = time + 2;
  707.     
  708.     if (self.message)
  709.     {
  710.         clientmsg (other, self.message);
  711.         sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
  712.     }
  713. };
  714.  
  715.  
  716. /*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
  717. Basic secret door. Slides back, then to the side. Angle determines direction.
  718. wait  = # of seconds before coming back
  719. 1st_left = 1st move is left of arrow
  720. 1st_down = 1st move is down from arrow
  721. always_shoot = even if targeted, keep shootable
  722. t_width = override WIDTH to move back (or height if going down)
  723. t_length = override LENGTH to move sideways
  724. "dmg"        damage to inflict when blocked (2 default)
  725.  
  726. If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
  727. "sounds"
  728. 1) medieval
  729. 2) metal
  730. 3) base
  731. */
  732.  
  733. void () func_door_secret =
  734. {
  735.     if (self.sounds == 0)
  736.         self.sounds = 3;
  737.     if (self.sounds == 1)
  738.     {
  739.         precache_sound ("doors/latch2.wav");
  740.         precache_sound ("doors/winch2.wav");
  741.         precache_sound ("doors/drclos4.wav");
  742.         self.noise1 = "doors/latch2.wav";
  743.         self.noise2 = "doors/winch2.wav";
  744.         self.noise3 = "doors/drclos4.wav";
  745.     }
  746.     if (self.sounds == 2)
  747.     {
  748.         precache_sound ("doors/airdoor1.wav");
  749.         precache_sound ("doors/airdoor2.wav");
  750.         self.noise2 = "doors/airdoor1.wav";
  751.         self.noise1 = "doors/airdoor2.wav";
  752.         self.noise3 = "doors/airdoor2.wav";
  753.     }
  754.     if (self.sounds == 3)
  755.     {
  756.         precache_sound ("doors/basesec1.wav");
  757.         precache_sound ("doors/basesec2.wav");
  758.         self.noise2 = "doors/basesec1.wav";
  759.         self.noise1 = "doors/basesec2.wav";
  760.         self.noise3 = "doors/basesec2.wav";
  761.     }
  762.  
  763.     if (!self.dmg)
  764.         self.dmg = 2;
  765.         
  766.     // Magic formula...
  767.     self.mangle = self.angles;
  768.     self.angles = '0 0 0';
  769.     self.solid = SOLID_BSP;
  770.     self.movetype = MOVETYPE_PUSH;
  771.     self.classname = "door";
  772.  
  773.     setmodel (self, self.model);
  774.     setorigin (self, self.origin);    
  775.     
  776.     self.touch = secret_touch;
  777.     self.blocked = secret_blocked;
  778.     self.speed = 50;
  779.     self.use = fd_secret_use;
  780.     if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
  781.     {
  782.         self.health = 10000;
  783.         self.takedamage = DAMAGE_YES;
  784.         self.th_pain = fd_secret_use;
  785.         self.th_die = fd_secret_use;
  786.     }
  787.     self.oldorigin = self.origin;
  788.     if (!self.wait)
  789.         self.wait = 5;        // 5 seconds before closing
  790. };
  791.